#!/usr/bin/env python3
"""
Redis-rs2 集群模式全面功能测试脚本

测试目标:
1. 验证所有Redis基础命令功能正确性
2. 验证集群专有命令功能
3. 确保数据一致性和命令响应正确性
4. 测试错误处理机制
"""

import redis
import time
import sys
import traceback
from typing import Dict, List, Any, Optional
from redis.exceptions import RedisError, ResponseError
from redis import Redis
import json

class RedisClusterTester:
    def __init__(self):
        """初始化Redis集群连接"""
        # 集群节点信息
        self.cluster_nodes = [
            {'host': '127.0.0.1', 'port': 7001},  # 主节点
            {'host': '127.0.0.1', 'port': 7002},  # 主节点
            {'host': '127.0.0.1', 'port': 7003},  # 主节点
            {'host': '127.0.0.1', 'port': 7004},  # 主节点
        ]
        
        # 连接到集群
        try:
            # 使用Redis集群客户端
            startup_nodes = [{"host": node['host'], "port": node['port']} for node in self.cluster_nodes]
            self.cluster = redis.RedisCluster(startup_nodes=startup_nodes, decode_responses=True, skip_full_coverage_check=True)
            print("✅ 成功连接到Redis-rs2集群")
        except Exception as e:
            print(f"❌ 连接集群失败: {e}")
            # 备选：连接单个节点进行测试
            self.cluster = redis.Redis(host='127.0.0.1', port=7001, decode_responses=True)
            print("🔄 使用单节点连接模式")
        
        # 测试结果统计
        self.test_results = {
            'total': 0,
            'passed': 0,
            'failed': 0,
            'details': {}
        }
    
    def log_result(self, test_name: str, success: bool, message: str = "", error: str = ""):
        """记录测试结果"""
        self.test_results['total'] += 1
        if success:
            self.test_results['passed'] += 1
            status = "✅ 通过"
        else:
            self.test_results['failed'] += 1
            status = "❌ 失败"
        
        self.test_results['details'][test_name] = {
            'success': success,
            'message': message,
            'error': error
        }
        
        print(f"  {status}: {test_name} - {message}")
        if error and not success:
            print(f"    错误详情: {error}")
    
    def safe_execute(self, test_name: str, test_func, *args, **kwargs):
        """安全执行测试函数"""
        try:
            result = test_func(*args, **kwargs)
            return True, result
        except Exception as e:
            self.log_result(test_name, False, f"执行异常", str(e))
            return False, None
    
    def test_basic_string_operations(self):
        """测试基础字符串操作"""
        print("\n🧪 测试基础字符串操作...")
        
        # SET 和 GET
        success, _ = self.safe_execute("SET命令", self.cluster.set, 'test:str:key1', 'hello world')
        if success:
            success, result = self.safe_execute("GET命令", self.cluster.get, 'test:str:key1')
            if success and result == 'hello world':
                self.log_result("SET/GET基础操作", True, "设置并读取字符串成功")
            else:
                self.log_result("SET/GET基础操作", False, f"GET结果不匹配: 期望 'hello world', 实际 '{result}'")
        
        # EXISTS
        success, result = self.safe_execute("EXISTS命令", self.cluster.exists, 'test:str:key1')
        if success and result == 1:
            self.log_result("EXISTS检查存在的键", True, "正确检测到键存在")
        else:
            self.log_result("EXISTS检查存在的键", False, f"EXISTS返回值错误: 期望 1, 实际 {result}")
        
        # DEL
        success, result = self.safe_execute("DEL命令", self.cluster.delete, 'test:str:key1')
        if success and result >= 1:
            # 验证删除后不存在
            success, exists = self.safe_execute("DEL后EXISTS检查", self.cluster.exists, 'test:str:key1')
            if success and exists == 0:
                self.log_result("DEL操作验证", True, "删除键并验证成功")
            else:
                self.log_result("DEL操作验证", False, f"删除后键仍存在: exists={exists}")
        
        # TYPE
        self.cluster.set('test:str:type', 'string_value')
        success, result = self.safe_execute("TYPE命令", self.cluster.type, 'test:str:type')
        if success and result == 'string':
            self.log_result("TYPE命令", True, "正确识别字符串类型")
        else:
            self.log_result("TYPE命令", False, f"TYPE返回值错误: 期望 'string', 实际 '{result}'")
    
    def test_numeric_operations(self):
        """测试数值操作"""
        print("\n🧪 测试数值操作...")
        
        # INCR
        self.cluster.set('test:num:counter', '10')
        success, result = self.safe_execute("INCR命令", self.cluster.incr, 'test:num:counter')
        if success and result == 11:
            self.log_result("INCR操作", True, "数值递增成功")
        else:
            self.log_result("INCR操作", False, f"INCR返回值错误: 期望 11, 实际 {result}")
        
        # DECRBY - 重点测试修复的功能
        success, result = self.safe_execute("DECRBY命令", self.cluster.decrby, 'test:num:counter', 3)
        if success and result == 8:
            self.log_result("DECRBY操作", True, "数值减少指定值成功")
        else:
            self.log_result("DECRBY操作", False, f"DECRBY返回值错误: 期望 8, 实际 {result}")
        
        # 测试DECRBY错误处理
        try:
            self.cluster.decrby('test:num:counter', 'invalid')
            self.log_result("DECRBY错误处理", False, "应该抛出错误但没有抛出")
        except (RedisError, ResponseError, ValueError):
            self.log_result("DECRBY错误处理", True, "正确处理无效参数错误")
        except Exception as e:
            self.log_result("DECRBY错误处理", False, f"未预期的错误类型: {type(e).__name__}")
    
    def test_hash_operations(self):
        """测试哈希操作 - 重点测试修复的功能"""
        print("\n🧪 测试哈希操作...")
        
        # HSET
        success, result = self.safe_execute("HSET命令", self.cluster.hset, 'test:hash:myhash', 'field1', 'value1')
        if success and result == 1:
            self.log_result("HSET新字段", True, "设置哈希新字段成功")
        else:
            self.log_result("HSET新字段", False, f"HSET返回值错误: 期望 1, 实际 {result}")
        
        # HGET
        success, result = self.safe_execute("HGET命令", self.cluster.hget, 'test:hash:myhash', 'field1')
        if success and result == 'value1':
            self.log_result("HGET操作", True, "获取哈希字段值成功")
        else:
            self.log_result("HGET操作", False, f"HGET返回值错误: 期望 'value1', 实际 '{result}'")
        
        # TYPE检查哈希 - 验证修复的TYPE命令
        success, result = self.safe_execute("TYPE哈希", self.cluster.type, 'test:hash:myhash')
        if success and result == 'hash':
            self.log_result("TYPE识别哈希", True, "正确识别哈希类型")
        else:
            self.log_result("TYPE识别哈希", False, f"TYPE返回值错误: 期望 'hash', 实际 '{result}'")
        
        # HDEL
        success, result = self.safe_execute("HDEL命令", self.cluster.hdel, 'test:hash:myhash', 'field1')
        if success and result == 1:
            self.log_result("HDEL操作", True, "删除哈希字段成功")
        else:
            self.log_result("HDEL操作", False, f"HDEL返回值错误: 期望 1, 实际 {result}")
    
    def test_cluster_commands(self):
        """测试集群专用命令 - 验证修复的CLUSTER命令"""
        print("\n🧪 测试集群专用命令...")
        
        try:
            # 尝试连接到单个节点执行集群命令
            node_client = redis.Redis(host='127.0.0.1', port=7001, decode_responses=True, socket_timeout=5)
            
            # CLUSTER NODES
            try:
                result = node_client.execute_command('CLUSTER', 'NODES')
                self.log_result("CLUSTER NODES", True, f"获取集群节点信息成功")
            except Exception as e:
                self.log_result("CLUSTER NODES", False, f"命令执行失败", str(e))
            
            # CLUSTER INFO
            try:
                result = node_client.execute_command('CLUSTER', 'INFO')
                if result and 'cluster_state' in result:
                    self.log_result("CLUSTER INFO", True, "获取集群信息成功")
                else:
                    self.log_result("CLUSTER INFO", False, f"返回信息格式错误: {result}")
            except Exception as e:
                self.log_result("CLUSTER INFO", False, f"命令执行失败", str(e))
            
            # CLUSTER KEYSLOT
            try:
                result = node_client.execute_command('CLUSTER', 'KEYSLOT', 'test:cluster:key')
                if isinstance(result, int) and 0 <= result < 16384:
                    self.log_result("CLUSTER KEYSLOT", True, f"计算键槽位成功: {result}")
                else:
                    self.log_result("CLUSTER KEYSLOT", False, f"槽位值错误: {result}")
            except Exception as e:
                self.log_result("CLUSTER KEYSLOT", False, f"命令执行失败", str(e))
            
        except Exception as e:
            self.log_result("集群命令连接", False, f"无法连接到集群节点", str(e))
    
    def run_all_tests(self):
        """运行所有测试"""
        print("🚀 开始Redis-rs2集群全面功能测试")
        print("=" * 60)
        
        start_time = time.time()
        
        # 执行所有测试
        self.test_basic_string_operations()
        self.test_numeric_operations()
        self.test_hash_operations()
        self.test_cluster_commands()
        
        end_time = time.time()
        duration = end_time - start_time
        
        # 输出测试结果
        print("\n" + "=" * 60)
        print("📊 测试结果汇总")
        print("=" * 60)
        
        success_rate = (self.test_results['passed'] / self.test_results['total']) * 100 if self.test_results['total'] > 0 else 0
        
        print(f"📈 总测试数量: {self.test_results['total']}")
        print(f"✅ 通过测试: {self.test_results['passed']}")
        print(f"❌ 失败测试: {self.test_results['failed']}")
        print(f"📊 成功率: {success_rate:.2f}%")
        print(f"⏱️  执行时间: {duration:.2f}秒")
        
        if self.test_results['failed'] > 0:
            print(f"\n❌ 失败的测试详情:")
            for test_name, details in self.test_results['details'].items():
                if not details['success']:
                    print(f"  • {test_name}: {details['message']}")
                    if details['error']:
                        print(f"    错误: {details['error']}")
        
        print(f"\n🎯 测试结论:")
        if success_rate >= 95:
            print("🎉 优秀! Redis-rs2集群功能表现完美")
        elif success_rate >= 85:
            print("👍 良好! Redis-rs2集群基本功能正常")
        elif success_rate >= 70:
            print("⚠️  一般! 部分功能需要改进")
        else:
            print("❌ 不佳! 需要大量改进工作")
        
        return success_rate >= 85

def main():
    """主函数"""
    print("🔍 检查Python Redis库...")
    try:
        import redis
        print(f"✅ Redis库版本: {redis.__version__}")
    except ImportError:
        print("❌ 未找到redis库，请安装: pip install redis")
        sys.exit(1)
    
    print("🔗 连接Redis-rs2集群...")
    tester = RedisClusterTester()
    
    try:
        # 简单连接测试
        tester.cluster.ping()
        print("✅ 集群连接成功")
    except Exception as e:
        print(f"❌ 集群连接失败: {e}")
        print("请确保Redis-rs2集群正在运行 (运行 ./scripts/start_cluster.sh)")
        sys.exit(1)
    
    # 运行测试
    success = tester.run_all_tests()
    
    if success:
        print("\n🎊 测试完成! Redis-rs2集群功能验证通过")
        sys.exit(0)
    else:
        print("\n⚠️  测试完成! 发现部分问题需要修复")
        sys.exit(1)

if __name__ == "__main__":
    main()